#include <stdint.h>
#include "../fe8.h"
#include "../gba_hack.h"


#define HACK
#ifndef CALL
typedef int (*callT)();
#define CALL(addr,...) ((callT)(addr))(__VA_ARGS__)
#define CALLT(addr,...) ((callT)(addr+1))(__VA_ARGS__)
#endif


/*
数据定义
85C4A94 地址存放这数据

分别为

使用
装备
交换
丢弃

*/
//////////////////////////////////////////////////////////////
//道具召唤
#define ItemUnit() (*((u32*)0x3004DF0))
#define ItemSelectIdx() (*((u8*)0x203A954+0x12))
#define GetSelectItem() (*(u16*)(ItemUnit()+0x1E + ItemSelectIdx()*2))
#define GetSelectItemId() (GetSelectItem()&0xff)

const u8    item_use_data[] = {
  //使用2个字节，第一个字节判断道具，第二个字节判断角色
#define set_summon(char_id,item)\
  item,char_id

#define set_item_limit(char_id,item) \
  item,char_id
  //set_summon(0x1,0x4e),
#include "../hack/item_limit.h"
  0,0
};

static int item_use_flg(u16 item,u8 char_id){
  u16 id = item&0xff;
  id |= (char_id<<8);
  u16 *ptr = item_use_data;
  while(*ptr){
    if(*ptr==id){
      return 1;
    }
    ptr++;
  }
  return 0;
}

static int item_use_limit(u16 item){
  u8 id = item & 0xff;
  u8 *ptr = item_use_data;
  while(*ptr){
    if(*ptr==id){
      return 1;
    }
    ptr+=2;
  }
  return 0;
}

static int item_use(){
  //return 1;//显示菜单，并可使用
  //return 2;   //显示菜单，但不可使用
  //return 3;     //不显示菜单
  return CALLT(0x8023640);
}

void summon_init3(u32 a0){
	//仿照 sub_80294C4()
	CALLT(0x801D730);
	CALLT(0x80011D0,0x02023CA8,0);
	CALLT(0x8001EFC,4);
	struct{
		u8	u0_[8];
        u8  u8_;
        u8  u9_;
        u8  uA_;
        u8  uB_;
        u32  uC_;
        u8  u10_;
		u8	u11_;
	}*ptr = (void*)0x203A954;
	  //ptr->u11_	=	3;		//此处为光之结界，如果改为7，则是召唤兽 ,8为召唤怪物,9同行?
	  ptr->u11_	=	7;
    //设置标记
    ptr->u8_    =   1;
}

u32 summon_init2(void*a1,void*a2){
	//仿照 sub_8029874
	u8*	v2	=	a2;
	struct{
		u8	u0_[0x13];
		u8	u13_;
		u8	u14_;
	}*ptr = (void*)0x203A954;
	ptr->u13_	=	v2[0];
	ptr->u14_	=	v2[1];
	//sub_80294C4(0);
	summon_init3(0);
	return 0x17;
}

void summon_init1(void*a1,void (*a2)(),u32 a3){
	//仿照sub_8029890函数
	a2(a1);
	CALLT(0x80194BC,(*(void**)0x202E4DC),-1);
	u32 v4 = CALLT(0x8050818,0x85C57B8,summon_init2);
	u32	v5 = CALLT(0x8009FA8,a3);
	CALLT(0x8035610,v4, v5);
	struct{
		u8	u0_[0x41];
		u8	u41_;
	}*ptr	=	(void*)0x202BCEC;
	if(!(ptr->u41_&2)){
		CALLT(0x80D4EF4,0x6a);
	}
}

int itemSummon(){

  //需要判断物品是否能召唤
  //return 3;   //退回一步
  //return 2;   //无法使用
  //return 4;     //无法使用
  //return 5;     //无法使用
  //return 33;      //关闭人物显示

    CALLT(0x804F610);
	  CALLT(0x8005660,0);
    //sub_80D65C8(ItemUnit(), sub_8026524, 2044,summon_init1);
    summon_init1(ItemUnit(), 0x8026524+1, 2044);

    if(*(u8*)(0x202BCEC+0x41)&2){
        CALLT(0x80D4EF4,106);
    }
    CALLT(0x804FCAC,CALLT(0x8003C50,CALLT(0x8003C68,0)));
    return 33;
}

//判断选择道具是否可召唤
int item_summon_flg(){
  //return 1;
  //获得选择道具
  uint16_t    item    = GetSelectItem();
  u8          item_id = item&0xff;
  u32         unit = ItemUnit();
  u8          char_id = getb(
  get(unit)   //获得角色指针
  +4);

  // u16 *ptr = (u16*)item_summon_data;
  // int  v = (char_id<<8) | item_id;
  // while(*ptr){
  //   if(*ptr==v){
  //     return 1;
  //   }
  //   ptr ++;
  // }
  if(item_use_flg(item,char_id)){
    return 1;
  }

  return 3;
}

static const u32 item_func[] = {
  //使用
0x80DCAC0
,0x65D0623, 0x3400,
//0x8023641
item_use,0
,0x8023734+1
,0, 0, 0

#ifdef HACK
,
0x80DCB88+2,      //召唤
0x65F061E,0x3400,
//0x8024391,        //判断道具是否可召唤
item_summon_flg,
0,
//0x8024468+1,    //默认不能召唤
itemSummon,
0,0,0
#endif

//装备
,0x80DCAB8
,0x65C0624, 0x3504, 0x80236B9, 0
,0x80237BC+1
,0, 0, 0

//交换
,0x80DCAB0
,0x6560625, 0x3604, 0x8022EFD, 0
,0x80237FC+1
,0,0,0

//丢弃
,0x80DCAA8
,0x65E0626, 0x3704, 0x8023701, 0
,0x8023830+1
,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

HACK_DATA(0x085C5600)
const u32 hook_item_menu = &item_func;

typedef struct{
  const char* name;
  u16     _04,                    //
  _06;        //0x65f,0x61e,      //菜单帮助
  u32     _08;            //0x5700
  void    *func;          //返回1，可以显示，返回3，不能显示
  u32     _10;            //0?
  void    *func2;         //如果点击这个选项，，如果执行nullsub, 则不执行任何
  u32     _18,_1c,_20;    //都为0
}_85C4A94;


//道具召唤结束
//////////////////////////////////////////////////////////////


// typedef struct{
//   uint16_t    item;       //可使用的道具
//   uint8_t     char_id;    //
// };

//可使用的角色id
const u8 *const use_item[0x100] = {
  [0xc0] = (const u8[]){1,2,0},
};

//没有问题
int JMP8023640_r1(uint32_t r0){
    uint32_t *r5 = (void*)0x3004DF0;
    uint8_t *r2 = (void*)0x203A954;

    uint16_t v1 =  //*(uint16_t*)(r5[0]+r2[0x12]*2);
      geth(get(0x3004DF0)+30+2*getb(0x203A966));

    //return 2;   //无法使用
    //return 3;     //没有使用选项
    //return 1;     //存在使用选项
    uint8_t id = v1&0xff;
    if(use_item[id]){
      //存在判断使用道具
      uint8_t *ptr = use_item[id];
      uint8_t char_id = getb(
      get(get(0x3004DF0)) //获得角色ROM指针
      +4);
      //获得角色id
      while(*ptr){
        if(char_id==*ptr){
          return 1;
        }
        ptr++;
      }
      return 2;
    }
    strh(0x0203fff0,v1);
    if(
        CALLT(0x80174E4,v1)
        && CALLT(0x80172F0,v1) != 4
        && CALLT(0x80172F0,v1) != 0xc
        && (!(CALLT(0x8017314,v1)&1) || CALLT(0x801631C,get(0x3004DF0),v1)<<24)
    ){
        if(CALLT(0x802881C,get(0x3004DF0),v1)<<24){
            return 1;
        }
        else{
            return 2;
        }
    }
    else{
        return 3;
    }
}

int hack(uint32_t r0);

const uint32_t list[] = {
0x4,
0x80297e1,
0x2,
0x8015385,
0x8,
0x85c29c8,
0x2,
0x8029591,
0x8,
0x85c29c8,
0x3,
0x8029645,
0x2,
0x8029771,
0x2,
(uint32_t)hack,
0xe,
0x0,
0x2,
0x8015395,
0x64000c,
0x0,
0x63000b,
0x0,
0x2,
0x80297ad,
0xe,
0x0,
0x2,
0x8015395,
0x64000b,
0x0,
0x0,
0x0,
};

int hack(uint32_t r0){
        *(int*)(0x203E1EC+0x54) = 0x8a1589c; //设置事件指针,这个是传送的动画 游戏事件
        //str(r0+0x54,0x8a1589c);

        int x = *(uint8_t*)(0x0203a967);
        int y = *(uint8_t*)(0x0203a968);

        int id = *(char*)(0x203A954+0xc); //获得当前角色

        uint32_t r = CALLT(0x8019108,id);
        str(0x203e1ec,r); //设置传送目标

        //
        //设置角色id
        // *(char*)(r+0x10) = x;
        // *(char*)(r+0x11) = y;

        *(char*)(0x203A568+0x73) = x;
        *(char*)(0x203A568+0x74) = y;


        //传送完成应该执行下面代码
        {
          *(char*)(0x203A954+0xe) = x;
          *(char*)(0x203A954+0xf) = y;
        }

        *(char*)(0x203a4e8+0x10) = x;
        *(char*)(0x203a4e8+0x11) = y;

        #if 1
        //消耗传送石头耐久
        u32 v4 = CALLT(0x8019108,getb(0x203A960));

        CALLT(0x802CA5C,v4,getb(0x203A966));
        CALLT(0x802CB8C,r0);
        #endif


        //CALLT(0x807fdec,r);
        //sub_8083F0C 设置目标传送位置


        //设置传送的动画
        CALLT(0x807CCA8,r0); //会创建一个新的游戏事件，地址为[0x203E1EC+0x54]值 8a1589c
    return 4;
}

#if 0
//OK，修改成功
int JMP802FB98_r1(uint32_t r0){
    uint32_t v0 = *(uint8_t*)(0x203A954+0xc);

    uint32_t r8 = CALLT(0x8017294,
    *(uint16_t*)(CALLT(0x8019108,v0) + 0x1e +
    *(uint8_t*)(0x203A954+0x12) * 2));
    *(uint8_t*)(0x203A4E8+0x7e) = 0;
    if(r8==0x9){
        r8 = 0x21 + 0x4b;
    }
    uint32_t v1 = r8 - 0x4b;
    if(v1<=0x76){
        switch (v1)
        {
        case 0:
        case 1:
        case 2:
        case 3:
            CALL(0x802EAD0+1,r0);break;
        case 6:
        case 7:
        case 8:
            CALL(0x802EF48+1,r0);break;
        case 0x5b:
            CALL(0x802F104+1,r0);break;
      case 4:
        CALLT(0x802F08C,r0);
        break;
      case 5:
        CALLT(0x802EB58,r0);
        break;
      case 0xA:
        CALLT(0x802EE30,r0);
        break;
      case 0xE:
        CALLT(0x802EBC4,r0);
        break;
      case 9:
        CALLT(0x802EEE4,r0);
        break;
      case 0xD:
        CALLT(0x802F1A0,r0);
        break;
      case 0xC:
        CALLT(0x802F1E0,r0);
        break;
      case 0x25:
        CALLT(0x802F3AC,r0);
        break;

      case 0x21:

      #ifndef HACK
      {
        CALLT(0x802F2A0,r0,10);
        break;
      }
      #endif
        //CALLT(0x805082C,r0);
        //CALLT(0x807fdec,r0);

        //807FDEC 设置目标传送地址

        //设置转移动画
        #if 0
        *(int*)(0x203E1EC+0x54) = 0x8a1589c; //设置事件指针


        #if 1
        int x = *(uint8_t*)(0x0203a967);
        int y = *(uint8_t*)(0x0203a968);

        int id = *(char*)(0x203A954+0xc); //当前角色ID,现在不能传送自己
        uint32_t r = CALLT(0x8019108,id);
        *(char*)(r+0x10) = x;
        *(char*)(r+0x11) = y;

        *(char*)(0x203A568+0x73) = x;
        *(char*)(0x203A568+0x74) = y;


        //传送完成应该执行下面代码
        {
          *(char*)(0x203A954+0xe) = x;
          *(char*)(0x203A954+0xf) = y;
        }

        // *(char*)(0x203a4e8+0x10) = x;
        // *(char*)(0x203a4e8+0x11) = y;




        CALLT(0x807CCA8,r0);
        #else
        CALLT(0x802EEE4,r0);
        CALLT(0x807CCA8,r0);
        #endif
        #endif

        //hack(r0);

        *(uint8_t*)(0x203a954+0xd) = *(char*)(0x203A954+0xc); //当前角色ID,现在不能传送自己;

        // int id = *(char*)(0x203A954+0xc); //当前角色ID,现在不能传送自己
        // uint32_t r = CALLT(0x8019108,id);
          //暂时先用1
        r0 = CALLT(0x8002BCC,list,3);   //
        *(uint32_t*)(r0+8)= (uint32_t)hack;
        return 4;
        break;
      case 0x57:
        CALLT(0x802F2A0,v1, 10);
        break;
      case 0x22:
        CALLT(0x802F304,v1);
        break;
      case 0x23:
        CALLT(0x802F370,v1);
        break;
      case 0x24:
        CALLT(0x802F3F0,v1);
        break;
      case 0x1E:
      case 0x1F:
      case 0x20:
      case 0x2E:
        CALLT(0x802F430);
        break;

      case 0x19:
      case 0x1A:
      case 0x1B:
      case 0x1C:
      case 0x1D:
      case 0x3D:
      case 0x3F:
      case 0x4C:
      case 0x4D:
      case 0x4E:
      case 0x76:
        //代码太多了，反正不会执行到这一步
        // uint32_t v6 = sub_8019108(*(uint8_t*)(0x203A954+0xc)) + 30 + 2 * *(uint8_t*)(0x203A4E8+0x12);
        // v203A5B2 = *(_WORD *)v6;
        // v203A532 = *(_WORD *)v6;
        // v7 = sub_8019108(v203A960);
        // v203A5B0 = sub_80168D0(v7);
        // v203A530 = v203A5B0;
        // v203A5D7 = -1;
        // sub_80D1730(v1);

        default:
            break;
        }
    }
    return 0;
}

#else
//修改一部分
void _802FEF4(){
  asm("mov r0,r0\n");
  asm("JMP802FEF4_r1:\n");
    asm("mov r1,r8\n"); //参数2
  asm("mov r8,r3\n");
  asm("mov r0,r6\n"); //参数1
  asm("\n");
  asm("bl h802FB98\n");
  asm("pop {r4,r5,r6,r7}\n");
  asm("pop {r0}\n");
  asm("bx  r0\n");
}

void h802FB98(uint32_t r0,uint16_t item){
  u8 item_id = item&0xff;
  // str(0x0203ffe0,r0);
  // str(0x0203ffe0+4,item);
  if(item_id==0x6c){
    //传送
      *(uint8_t*)(0x203a954+0xd) = *(char*)(0x203A954+0xc); //当前角色ID,现在不能传送自己;

      // int id = *(char*)(0x203A954+0xc); //当前角色ID,现在不能传送自己
      // uint32_t r = CALLT(0x8019108,id);
        //暂时先用1

        #if 0
        //消耗传送石头耐久
        u32 v4 = CALLT(0x8019108,getb(0x203A960));

        CALLT(0x802CA5C,v4,getb(0x203A966));
        CALLT(0x802CB8C,r0);
        #endif


      r0 = CALLT(0x8002BCC,list,3);         //设置传送位置
      //*(uint32_t*)(r0+8)= (uint32_t)hack;   //确定是触发，如果不注释这个，取消时，将会置为[0，0]
      return;
  }
}


#endif

//////////////////////////////////////////
//判断道具是否能使用
int item_att(u32 a1,u16 item){
  u8 char_id = getb(get(a1)+4);
  if(item_use_limit(item)){
    if(item_use_flg(item,char_id)){
      return 1; //可以使用
    }
    return 0;   //无法使用
  }
  return 10;    //继续后续的判断
  //return 0;
}

#define nasm(s) asm(s);asm("\n");
int _801631C_(){
  nasm("mov r0,r0");
  nasm("JMP801631C_r2:");
  nasm("push {r4,r5,lr}");
  nasm("mov r4,r0");
  nasm("mov r5,r1");
  nasm("bl  item_att");
  nasm("cmp r0,#8");
  nasm("blt _801631C_quit2");     //小于8，则直接退出
  nasm("cmp r5,#0");
  nasm("beq _801631C_quit")
  nasm("ldr r1,=0x8016328+1");
  nasm("bx r1");
  nasm("_801631C_quit:")
  nasm("mov r0,#0")
  nasm("_801631C_quit2:")
  nasm("pop {r4,r5}\n");
  nasm("pop {r1}");
  nasm("bx r1");
}
